home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
interf.aqm
/
interf.asm
Wrap
Assembly Source File
|
1985-11-26
|
20KB
|
453 lines
; Keyin/Display/Clock Interface Routines.
;
; These routines provide a standard interface to the keyboard and
; display of the IBM personal computer.
;
; Copyright 1983 by John Cole, Duncanville, Texas.
;
;
; This routine is the interface to the display of the machine. It
; interprets a string of characters terminated by either a C$EOS
; character or a carriage return, sending the non-control characters
; to the display, and interpreting the controls to perform various
; functions.
;
; ON ENTRY:
; SI -- ADDRESS OF STRING TO BE DISPLAYED.
;
; ON EXIT:
; SI -- POINTS PAST LAST CHARACTER DISPLAYED.
; DL -- INDETERMINATE.
; AL -- INDETERMINATE.
;
; Equates for the various control characters
;
C$NUL EQU 00H ; NULL CHARACTER
C$EOS EQU 03H ; DISPLAY STRING TERMINATOR
C$BELL EQU 07H ; BELL CHARACTER
C$CPOS EQU 09H ; CURSOR POSITION (H,V) FOLLOWS
C$CR EQU 0DH ; END WITH CARRIAGE RETURN, LINE FEED
C$LF EQU 0AH ; LINE FEED
C$BS EQU 08H ; BACKSPACE
C$EEOF EQU 011H ; ERASE TO END OF FRAME
C$EEOL EQU 012H ; ERASE TO END OF LINE
C$RU EQU 013H ; SCROLL THE SCREEN UP
C$RD EQU 014H ; SCROLL THE SCREEN DOWN
C$ESC EQU 01BH ; ESCAPE/CANCEL
;
;Macro Definitions
;
SVC MACRO FUNC
MOV AH,FUNC
INT 21H
ENDM
;
BIOS MACRO FUNC
INT 10H
ENDM
;
;
;
S$DSPLY PROC NEAR ; DISPLAY PROCEDURE
PUSH BX ; SAVE REGISTERS
;
S$DSPLY0:
MOV DL,[SI] ; GET THE CHARACTER
INC SI ; MOVE THE POINTER
CMP DL,C$EOS ; SEE IF END OF STRING
JNE S$DSPLY1 ; BRANCH IF NOT
POP BX ; RESTORE REGISTERS
RET ; ELSE EXIT
;
; HERE CHECK FOR THE VARIOUS CONTROL CHARACTERS, AND TAKE APPROPRIATE
; ACTION IF WE GET THEM. THE FIRST CODE IS SCROLL UP.
;
S$DSPLY1: CMP DL,C$RU ; SEE IF ROLL UP
JNE S$DSPLY1A ; IF NOT, TRY SOMETHING ELSE
;
MOV CX,0 ; SET TOP OF SCREEN
MOV DX,2479H ; SET BOTTOM OF SCREEN WINDOW
MOV BH,7 ; ATTRIBUTE OF BLANK LINE
MOV AX,601H ; SET SCROLL CODE FOR BIOS, 1 LINE
BIOS
JMP S$DSPLY0 ; LOOP BACK FOR NEXT CHARACTER
;
; CHECK FOR SCROLL DOWN.
;
S$DSPLY1A:
CMP DL,C$RD ; CHECK FOR ROLL-DOWN CODE
JNE S$DSPLY2 ; JUMP IF NOT
MOV CX,0 ; SET TOP POSITION
MOV DX,2479H ; AND BOTTOM OF SCREEN
MOV BH,7 ; ATTRIBUTES OF BLANK LINE
MOV AX,701H ; SCROLL 1 LINE, BIOS CODE IN AH
BIOS ; DO IT
JMP S$DSPLY0 ; BACK FOR NEXT CHARACTER
;
; CHECK FOR CURSOR POSITONING HERE.
;
S$DSPLY2:
CMP DL,C$CPOS ; CHECK IT
JNE S$DSPLY3 ; JUMP IF NOT EQUAL
MOV AH,2 ; FUNCTION NUMBER
MOV DX,[SI] ; GET POSITION
ADD SI,2 ; MOVE PAST THE POSITION
MOV BH,0 ; SET DISPLAY PAGE
BIOS ; CALL BIOS FOR DISPLAY CONTROL
JMP S$DSPLY0 ; LOOP BACK FOR NEXT CHARACTER
;
; CHECK FOR CARRIAGE RETURN, WHICH DOES A LINE FEED AS WELL. THIS IS
; ALSO TREATED AS A STRING TERMINATOR.
;
S$DSPLY3:
CMP DL,C$CR ; CHECK FOR CARRIAGE RETURN
JNE S$DSPLY4 ; JUMP IF NOT
SVC DSPCHAR$ ; ELSE PUT OUT THE CHARACTER
POP BX ; RESTORE REGISTERS
RET ; AND EXIT
;
; ERASE SCREEN FROM CURRENT CURSOR POSITION TO END OF FRAME. THE
; LOGIC IS TO READ THE CURRENT CURSOR POSITION, THEN WRITE BLANKS TO
; THE SCREEN FROM THERE TO THE END OF THE SCREEN. FINALLY, WE RESET
; THE CURSOR POSITION TO ITS FORMER VALUE.
;
S$DSPLY4:
CMP DL,C$EEOF ; CHECK FOR ERASE TO END OF FRAME CODE
JNE S$DSPLY5 ; IF NOT, TRY NEXT ONE
;
MOV AH,3 ; CODE FOR READING THE CURSOR POSITION
BIOS ; GET IT
PUSH DX ; AND STACK IT
CALL S$SCLR ; CLEAR THE REMAINDER OF THIS LINE
POP DX ; RESTORE ORIGINAL CURSOR POSITION
MOV AH,2 ; SET ORIGINAL CURSOR POSITION
BIOS
JMP S$DSPLY0 ; AND LOOP BACK
;
; CHECK FOR ERASE TO END OF LINE CODE. IF SO, JUST CALL THE ROUTINE
; TO CLEAR THE END OF THE LINE, THEN RESTORE THE CURRENT CURSOR.
;
S$DSPLY5:
CMP DL,C$EEOL ; CHECK FOR THE CODE
JNE S$DSPLY8 ; IF NOT, TRY SOMETHING ELSE
;
MOV AH,3 ; READ CURSOR POSITION
BIOS ; GET IT
PUSH DX ; AND STACK IT
CALL S$DCLR ; CLEAR THE REST OF THIS LINE
POP DX ; RESTORE OLD CURSOR POSITION
MOV AH,2 ;
BIOS ;
JMP S$DSPLY0 ; AND BACK TO THE MAIN LOOP
;
; CHECK FOR BELL CHARACTER, CAUSES BEEP.
;
S$DSPLY8:
CMP DL,C$BELL ; TRY BELL CHARACTER
JNE S$DSPLY9 ; JUMP IF NOT
;
CALL S$BEEP ; BEEP THE SPEAKER
JMP S$DSPLY0 ; AND RETURN TO THE LOOP
;
; HERE THE CHARACTER IS NOT ONE OF THE CONTROLS, SO JUST OUTPUT IT
; TO THE SCREEN, THEN LOOP.
;
S$DSPLY9: SVC DSPCHAR$ ; DISPLAY THE CHARACTER
JMP S$DSPLY0 ; AND LOOP BACK
;
;
; SUBROUTINE TO CLEAR A SINGLE ROW FROM THE POSITION IN DL TO THE
; END OF THE LINE. ON EXIT, DL HAS ZERO.
;
S$DCLR:
PUSH DX ; SAVE POSITION OVER LOOP
MOV DH,80 ; SET MAXIMUM VALUE
SUB DH,DL ; COMPUTE NUMBER OF COLUMNS TO CLEAR
MOV DL,' ' ; FILL CHARACTER
;
S$DCLR1:
SVC DSPCHAR$ ; WRITE THE CHARACTER
DEC DH ; DECREMENT THE COUNTER
JNZ S$DCLR1 ; LOOP BACK IF NOT DONE
POP DX ; RESTORE THE POSITION
MOV DL,0 ; CLEAR COLUMN NUMBER
RET ; AND EXIT
S$DSPLY ENDP
;
; SUBROUTINE TO CLEAR THE SCREEN FROM THE CURSOR POSITION TO THE END OF
; THE SCREEN.
;
S$SCLR: PUSH CX ; SAVE SOME REGISTERS
PUSH ES ;
PUSH DI ;
MOV AL,DH ; GET CURSOR ROW
PUSH DX ; STACK CURSOR POSITION
MOV DX,160 ; NUMBER OF BYTES IN A ROW
MOV AH,0 ; CLEAR HIGH BYTE
MUL DL ; COMPUTE OFFSET FOR ROW
POP DX ; RESTORE POSITION
MOV DH,0 ; CLEAR HIGH BYTE OF COLUMN
SAL DX,1 ; COMPUTE IN WORDS
ADD AX,DX ; COMPUTE OFFSET
MOV DI,AX ; COPY TO PROPER REGISTER
PUSH DI ; STACK BUFFER OFFSET
INT 11H ; GET EQUIPMENT TYPE
MOV DI,AX ; COPY IT
MOV AX,0B800H ; SEGMENT ADDRESS FOR COLOR CARD
AND DI,30H ; SEE IF COLOR OR BLACK AND WHITE CARD
CMP DI,30H ;
JNE S$SCLR1 ; JUMP IF COLOR
MOV AX,0B000H ; SET UP BLACK AND WHITE
S$SCLR1: POP DI ; RESTORE BUFFER OFFSET
MOV ES,AX ; SET UP CARD BASE AS EXTRA SEGMENT
MOV CX,80*25*2 ; FILL LENGTH IN WORDS
SUB CX,DI ; SUBTRACT OFF LENGTH BEFORE POSITION
MOV AX,' '+7*256 ; FILL CHARACTER AND ATTRIBUTE
REP STOSW ; STORE IT ALL
POP DI ; RESTORE REGISTERS
POP ES ;
POP CX ;
RET ; BACK TO CALLER
;
PAGE
;
; CHARACTER DISPLAY SUBROUTINE.
;
; THIS ROUTINE PUTS THE CHARACTER ON THE SCREEN. HOWEVER, IF IT WOULD
; GO PAST THE END OF THE LINE, NO WRAPAROUND TAKES PLACE.
;
S$DSPCHR PROC NEAR ; ENTRY POINT FOR CHARACTER DISPLAY
PUSH BX ; STACK ATTRIBUTE
PUSH CX ; AND COUNTER REGISTER
PUSH DX ;
MOV CX,1 ; ONLY ONE CHARACTER GOING OUT
MOV BH,0 ; DISPLAY PAGE IN USE
MOV AH,9 ; DISPLAY CHARACTER/ATTRIBUTE
INT 10H ; CALL THE ROM
MOV AH,3 ; GET CURRENT CURSOR POSITION
INT 10H ;
CMP DL,79 ; CHECK FOR PAST END OF LINE
JE S$DSPCHR1 ;
INC DL ; IF NOT, MOVE TO NEXT COLUMN
MOV AH,2 ; NOW SET THE CURSOR
INT 10H ;
S$DSPCHR1: POP DX ;
POP CX ; RESTORE REGISTERS
POP BX ; . . .
RET ; AND BACK TO CALLER
S$DSPCHR ENDP ; END OF CHARACTER DISPLAY PROCEDURE
;
;
; RETURN CURRENT CURSOR POSITION.
;
S$CURPOS PROC NEAR ; GET CURSOR POSITION IN DX
PUSH CX ; STACK OVER CALL
PUSH BX ;
MOV BH,0 ; SET THE DISPLAY PAGE
MOV AH,3 ; VIDEO I/O PARAMETER
INT 10H ; CALL THE ROM
POP BX ; RESTORE CALLER'S BX
POP CX ; RESTORE CALLER'S CX
RET ; EXIT WITH POSITION
S$CURPOS ENDP ; END OF PROCEDURE
;
;
PAGE
;
; Routine to key in a line of a specified length into a buffer.
;
; On entry:
; SI -- Address of buffer.
; CX -- Number of characters to accept.
;
; On Exit:
; SI -- Unchanged.
;
S$KEYIN PROC NEAR ; PROCEDURE ENTRY POINT
PUSH SI ; STACK BUFFER ADDRESS
;
S$KEYIN0: SVC KEYINX$ ; GET A CHARACTER
;
; CHECK FOR BACKSPACE AND CANCEL HERE.
;
CMP AL,C$ESC ; CHECK FOR ESCAPE
JE S$KEYINA ; JUMP IF SO
CMP AL,C$BS ; TEST WHAT WE GOT
JNE S$KEYIN3 ; IF NOT, WAS SOMETHING ELSE
;
S$KEYINA: MOV BP,SP ; GET STACK POINTER
MOV DH,AL ; COPY CHARACTER THAT GOT US HERE
S$KEYINB: CMP SI,[BP] ; CHECK FOR BEGINNING OF LINE
JE S$KEYIN0 ; LOOP BACK IF SO
MOV DL,C$BS ; GET A BACKSPACE
SVC DSPCHAR$ ; BACK OVER CHARACTER
MOV DL,' ' ; GET BLANK FOR CURRENT POSITION
SVC DSPCHAR$ ; PUT IT OUT
MOV DL,C$BS ; NOW BACKSPACE AGAIN
SVC DSPCHAR$ ; SINCE WE HAVE PUT OUT THE BLANK
INC CX ; AND INCREMENT THE COUNTER
DEC SI ; BACK UP STORAGE POINTER
CMP DH,C$ESC ; CHECK FOR ESCAPE/CANCEL
JE S$KEYINB ; LOOP BACK IF SO
JMP S$KEYIN0 ; AND LOOP BACK FOR THE NEXT ONE
;
S$KEYIN3:
MOV [SI],AL ; STORE IT
INC SI ; MOVE THE POINTER
CMP AL,C$CR ; CHECK FOR CARRIAGE RETURN
JNE S$KEYIN4 ; JUMP IF NOT
POP SI ; RESTORE STRING ADDRESS
RET ; ELSE EXIT IF END OF LINE
;
S$KEYIN4: MOV DL,AL ; COPY THE CHARACTER
SVC DSPCHAR$ ; PUT IT ON THE SCREEN
LOOPNZ S$KEYIN0 ; LOOP BACK FOR NEXT CHARACTER
;
; HERE THE COUNTER HAS DECREMENTED TO ZERO, SO WE SIT IN A HARD LOOP
; WAITING FOR A CARRIAGE RETURN.
;
S$KEYIN5: SVC KEYINX$ ; GET A CHARACTER
CMP AL,C$CR ; CHECK FOR END
JE S$KEYIN6 ; EXIT IF IT IS
CMP AL,C$BS ; CHECK FOR BACKSPACE
JE S$KEYINA ; TAKE CARE OF THAT IF SO
CMP AL,C$ESC ; CHECK FOR ESCAPE, TREATED AS CANCEL
JE S$KEYINA ; AND JUMP IF SO
CALL S$BEEP ; BEEP
MOV DL,C$BS ; GET BACKSPACE
SVC DSPCHAR$ ; AND BACK OVER BAD CHARACTER
JMP S$KEYIN5 ; AND LOOP BACK
;
S$KEYIN6: MOV [SI],AL ; STORE THE TERMINATOR
POP SI ; RESTORE STRING ADDRESS
RET ; AND EXIT
S$KEYIN ENDP
;
PAGE
; BEEP ROUTINE
;
; THIS ROUTINE CAUSES A BEEP AT THE SPEAKER OF THE PC.
;
TIMER$ EQU 40H ; TIMER PORT
PORT$B EQU 61H ; 8255 PORT B ADDRESS
;
S$BEEP PROC NEAR ; START OF PROCEDURE
MOV AL,10110110B ; GET TIMER SETTING
OUT TIMER$+3,AL ; SET TIMER MODE
MOV AX,533H ; DIVISOR FOR 1000 HZ
OUT TIMER$+2,AL ; SET COUNT LSB
MOV AL,AH ;
OUT TIMER$+2,AL ; SET COUNT MSB
IN AL,PORT$B ; GET CURRENT PORT MODE
MOV AH,AL ; SAVE IT
OR AL,3 ; TURN SPEAKER ON
OUT PORT$B,AL
MOV CX,32762 ; COUNTER FOR ABOUT 250 MS WAIT
S$BEEP1: LOOP S$BEEP1 ; DELAY BEFORE TURNING OFF
MOV AL,AH ; RECOVER OLD PORT VALUE
OUT PORT$B,AL ; SET IT THE WAY IT WAS
RET ; AND EXIT TO CALLER
S$BEEP ENDP ; END OF ROUTINE
;
PAGE
;
; GET TIME AS A STRING.
;
; This routine returns a string containing the current time as read
; from the system clock. The string is of the form HH:MM:SS.
;
; On entry:
; SI -- Address into which string is to be placed.
;
; On Exit:
; AX -- Changed.
;
S$TIME PROC NEAR ; START OF TIME PROCEDURE
PUSH SI ; STACK INCOMING REGISTERS
PUSH DX ; . . .
PUSH CX ; . . .
SVC TIME$ ; GET THE TIME
PUSH DX ; STACK SECONDS
MOV AL,CH ; THE HOURS ARE GOOD
CBW ; CONVERT TO WORD
MOV DL,10 ; SEPARATE THE DIGITS
DIV DL ;
ADD AX,'00' ; CONVERT TO ASCII
MOV [SI],AX ; SAVE HOURS
MOV BYTE PTR 2[SI],':' ; STORE SEPARATOR
ADD SI,3 ; MOVE STORE POINTER
MOV AL,CL ; NOW GET THE MINUTES
CBW ; CONVERT
MOV DL,10 ; GET DIVISOR
DIV DL ; SPLIT THE DIGITS
ADD AX,'00' ; CONVERT TO ASCII
MOV [SI],AX ; STORE IT, LSB,MSB
MOV BYTE PTR 2[SI],':' ; AND KEEP THEM APART
ADD SI,3 ; MOVE MICKEY'S BIG HAND
POP DX ; RESTORE SECONDS
MOV AL,DH ; SECONDS, PLEASE
CBW ; CLEAR HIGH BYTE OF DIVIDEND
MOV DL,10 ; DIVISOR
DIV DL ; SPLIT
ADD AX,'00' ; CONVERT TO ASCII
MOV [SI],AX ; STORE
POP CX ; RESTORE CALLER'S REGISTERS
POP DX ; . . .
POP SI ; . . .
RET ; AND GO HOME
S$TIME ENDP ; END OF TIME CONVERSION
;
PAGE
;
; DATE CONVERSION ROUTINE.
;
; This routine gets the system date and converts it into a string of
; the form MM/DD/YY.
;
; On Entry:
; SI -- Address into which date is to be returned.
;
; On Exit:
; AX -- Changed.
; All other registers preserved.
;
S$DATE PROC NEAR ; DATE CONVERSION PROCEDURE
PUSH SI ; STACK CALLER'S REGISTERS
PUSH CX ; . . .
PUSH DX ; . . .
SVC DATE$ ; CALL UP THE DATE
PUSH DX ; SAVE THE DAY
MOV AL,DH ; GET THE MONTH
CBW ; EXPAND IT OUT
MOV DL,10 ; GET DIVISOR
DIV DL ; CONVERT MONTH
ADD AX,'00' ; CONVERT TO ASCII
MOV [SI],AX ; STORE IT
MOV BYTE PTR 2[SI],'/' ; STORE SEPARATOR
ADD SI,3 ; MOVE TO DAY
POP DX ; RESTORE FROM STACK
MOV AL,DL ; WHAT DAY IS IT?
CBW ; EXPAND IT
MOV DL,10 ; DIVISOR
DIV DL ; SPLIT THE DIGITS APART
ADD AX,'00' ; CONVERT TO ASCII
MOV [SI],AX ; STORE IT
MOV BYTE PTR 2[SI],'/' ; STORE SEPARATOR
ADD SI,3 ; MOVE TO YEAR
SUB CX,1900 ; SUBTRACT BIAS FROM YEAR
CMP CX,100 ; SEE IF TURN OF MILLENIUM PAST
JL S$DATE1 ; JUMP IF NOT (HIGH PROBABILITY)
SUB CX,100 ; ELSE MAKE SURE WE GET JUST 2 DIGITS
S$DATE1: MOV AL,CL ; GET THE YEAR
CBW ; CLEAR HIGH BYTE
MOV DL,10 ; DIVISOR
DIV DL ; SPLIT
ADD AX,'00' ; CONVERT
MOV [SI],AX ; STORE
POP DX ; RESTORE CALLER'S REGISTERS
POP CX ; . . .
POP SI ; . . .
RET ; EXIT TO CALLER
S$DATE ENDP ; THE DATE IS OVER